package com.lijiajia.cloud.authserver.security.oauth.client;

import com.lijiajia.cloud.authserver.pojo.mongodb.Client;
import com.lijiajia.cloud.authserver.service.ClientService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 客户端详细信息服务 mongodb实现
 */
public class MongoClientDetailsService implements ClientDetailsService, ClientRegistrationService {
    private ClientService clientService;

    public MongoClientDetailsService(ClientService clientService) {
        this.clientService = clientService;
    }

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        Client client = clientService.findById(clientId)
                .orElseThrow(() -> new NoSuchClientException("No client with requested id: " + clientId));
        return convertClient(client);
    }

    private ClientDetails convertClient(Client client) {
        BaseClientDetails clientDetails = new BaseClientDetails();
        clientDetails.setClientId(client.getId());
        clientDetails.setClientSecret(client.getSecret());
        clientDetails.setAuthorizedGrantTypes(client.getAuthorizedGrantTypes());
        clientDetails.setResourceIds(client.getResourceIds());
        clientDetails.setScope(client.getScope());
        clientDetails.setAutoApproveScopes(client.getAutoApproveScopes());
        clientDetails.setAuthorities(client.getAuthorities().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toUnmodifiableSet()));
        clientDetails.setRegisteredRedirectUri(client.getRedirectUris());
        clientDetails.setAccessTokenValiditySeconds(client.getAccessTokenValiditySeconds());
        clientDetails.setRefreshTokenValiditySeconds(client.getRefreshTokenValiditySeconds());
        clientDetails.setAdditionalInformation(client.getAdditionalInformation());
        return clientDetails;
    }

    private Client convertClientDetails(ClientDetails clientDetails) {
        Client client = new Client()
                .setId(clientDetails.getClientId())
                .setSecret(clientDetails.getClientSecret())
                .setAuthorizedGrantTypes(clientDetails.getAuthorizedGrantTypes())
                .setResourceIds(clientDetails.getResourceIds())
                .setScope(clientDetails.getScope())
                .setAuthorities(clientDetails.getAuthorizedGrantTypes())
                .setRedirectUris(clientDetails.getRegisteredRedirectUri())
                .setAccessTokenValiditySeconds(clientDetails.getAccessTokenValiditySeconds())
                .setRefreshTokenValiditySeconds(clientDetails.getRefreshTokenValiditySeconds())
                .setAdditionalInformation(clientDetails.getAdditionalInformation());

        if (clientDetails instanceof BaseClientDetails) {
            client.setAutoApproveScopes(client.getAutoApproveScopes());
        }
        return client;
    }

    @Override
    public void addClientDetails(ClientDetails clientDetails) throws ClientAlreadyExistsException {
        clientService.save(convertClientDetails(clientDetails));
    }

    @Override
    public void updateClientDetails(ClientDetails clientDetails) throws NoSuchClientException {
        clientService.save(convertClientDetails(clientDetails));
    }

    @Override
    public void updateClientSecret(String clientId, String secret) throws NoSuchClientException {
        clientService.save(new Client().setId(clientId).setSecret(secret));
    }

    @Override
    public void removeClientDetails(String clientId) throws NoSuchClientException {
        clientService.deleteById(clientId);
    }

    @Override
    public List<ClientDetails> listClientDetails() {
        return clientService.find().stream().map(this::convertClient).collect(Collectors.toList());
    }
}
